#include "TcpServer.h"
#include <unistd.h>
#include <cstring>
#include <functional>
#include <iostream>

using namespace std;
TcpServer::TcpServer(const std::string& ip,
                     const unsigned short port,
                     int maxEvent)
    : loop_(maxEvent) {
    acceptor_ = new Acceptor(&loop_, ip, port);
    acceptor_->setAcceptCb(
        std::bind(&TcpServer::acceptCb, this, std::placeholders::_1));

    // threadNums_ = std::thread::hardware_concurrency();
    threadNums_ = 1;
    IoThreads_ = new ThreadPool;
    IoThreads_->Start(threadNums_);

    workerThreads_ = new ThreadPool;
    workerThreads_->Start(threadNums_);

    subLoops_.reserve(threadNums_);
    for (int i = 0; i < threadNums_; i++) {
        subLoops_.push_back(new EventLoop);
        // 将子线程的loop交给Io线程处理
        IoThreads_->submitTask(std::bind(&EventLoop::Loop, subLoops_[i]));
    }
}
void TcpServer::Run() {
    loop_.Loop();
}
void TcpServer::Stop() {
    for (auto& it : subLoops_) {
        it->stop();
    }
    loop_.stop();
}
TcpServer::~TcpServer() {
    delete acceptor_;
    // 先停止IO循环里面的的所有循环，唤醒之后退出即可
    for (auto& it : subLoops_) {
        while(it->isRunning());
        delete it;
    }
    delete IoThreads_;
    delete workerThreads_;
}

void TcpServer::acceptCb(Socket* clientSock) {
    clientSock->setNonBlock();
    // 分配给不同的subLoops
    static int index = 0;
    index %= threadNums_;
    cout << "index: " << index << endl;
    EventLoop* subLoop = subLoops_[index];
    index++;
    auto conn = make_shared<Connection>(subLoop, clientSock);
    cout << "has new client connection: ";
    conn->showInfo() << endl;

    conn->setExitCb(std::bind(&TcpServer::onExit, this, std::placeholders::_1));
    conn->setErrorCb(
        std::bind(&TcpServer::onError, this, std::placeholders::_1));
    conn->setMessageCb(std::bind(&TcpServer::onMessage, this,
                                 std::placeholders::_1, placeholders::_2));

    conns_.insert({clientSock->GetFd(), conn});
}

// 异常退出
void TcpServer::onError(ConnectionSptr conn) {
    // todo 给socket设置，打印哪个ip和端口异常退出了
    perror("error: ");
    onExit(conn);
}
void TcpServer::onExit(ConnectionSptr conn) {
    // todo 给socket设置，打印哪个ip和端口下线了
    conn->close();
    conn->showInfo() << "has exit\n";
    
    lock_guard<mutex> lock(connsMtx_);
    conns_.erase(conn->getFd());
}
// 客户端收到消息时
void TcpServer::onMessage(ConnectionSptr conn, const string msg) {
    // 业务处理交给工作线程
    workerThreads_->submitTask(
        std::bind(&TcpServer::workerTask, this, conn, msg));
}

// 每个工作线程处理的业务
void TcpServer::workerTask(ConnectionSptr conn, const string& msg) {
    cout << "recv: " << msg << endl;
    conn->sendMsg(msg);
}
